/**
 * @version 2007-1-5
 * @author xalinx at gmail dot com
 */
package org.nanhill.commons.pattern.flow;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Action and View states flow.
 * 
 * @version 2007-1-5
 * @author xalinx at gmail dot com
 * 
 */
public class ActionViewFlow extends AbstractFlow {

	private Map<String, Event> eventDepot = new HashMap<String, Event>();

	private Map<String, State> stateDepot = new HashMap<String, State>();

	public void addEvent(Event event) {
		eventDepot.put(event.getId(), event);
	}

	public void addState(State state) {
		stateDepot.put(state.getId(), state);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.commons.pattern.automaton.StateAutomaton#getState(java.lang.String)
	 */
	public State getState(String stateId) {
		return stateDepot.get(stateId);
	}

	public State transit(String eventId) {
		State toState = this.getStartState();
		if (null != eventId) {
			Event curEvent = eventDepot.get(eventId);
			if (null != curEvent)
				toState = curEvent.getTo();
		}
		return toState;
	}

	public ViewState nextViewState(ActionContext context) throws FlowException {
		ViewState view = null;
		State state = this.transit(context.getEventId());
		while (true) {
			if (ViewState.class.isAssignableFrom(state.getClass())) {
				view = (ViewState) state;
				break;
			} else {
				ActionState as = (ActionState) state;
				Action action = as.getAction();

				// do action method
				Object target = action.getTarget();
				Method targetMethod = action.getTargetMethod();
				try {
					targetMethod.invoke(target, context);
					state = as.getOkState();
				} catch (Exception e) {
					State errorState = as.getErrorState();
					if (null == errorState) {
						throw new FlowException(
								"action target method invoke error:", e);
					}
					state = errorState;
				}
			}
		}
		return view;
	}

}
